#include <string.h>
#include <kernel.h>

void kernel_strcpy(char *dst, const char *src)
{
    if (!src) return;

    while (*src) 
        *dst++ = *src++;

    *dst = '\0';
}

void kernel_strncpy(char *dst, const char *src, uint32_t size)
{
    if (!dst || !src || !size) return;

    char *d = dst;
    const char *s = src;
    while ((size -- > 0) && (*s)) 
        *dst++ = *src++;

    if (size == 0) *(d - 1) = '\0'; else *d = '\0';
}

int kernel_strncmp(const char *str1, const char *str2, uint32_t size)
{
    if (!str1 || !str2 || !size) return -1;

    while (*str1 && *str2 && (*str1 == *str2) && size)
    {
        str1++;
        str2++;
    }

    return !((*str1 == '\0') || (*str2 == '\0') || (*str2 == *str2));
}

uint32_t kernel_strlen(const char *str)
{
    if (!str) return 0;

    const char *c = str;
    uint32_t length = 0;
    while (*c++) 
        length++;

    return length;
}

void kernel_memcpy(void *dst, void *src, uint32_t size)
{
    if (!dst || !src || !size) return;

    uint8_t *s = (uint8_t *)src;
    uint8_t *d = (uint8_t *)dst;
    while (size--) 
        *d++ = *s++;
}

void kernel_memset(void *dst, uint8_t value, uint32_t size)
{
    if (!dst || !size) return;
    uint8_t *d = (uint8_t *)dst;
    while (size--) 
        *d++ = value;
}

int kernel_memcmp(void *v1, void *v2, uint32_t size)
{
    if (!v1 || !v2 || !size) return -1;

    uint8_t *p1 = (uint8_t *)v1;
    uint8_t *p2 = (uint8_t *)v2;
    while (size--)
        if (*p1++ != *p2++) return 1;
    
    return 0;
}

void kernel_itoa(char * buf, int num, int base) 
{
    // 转换字符索引[-15, -14, ...-1, 0, 1, ...., 14, 15]
    static const char * num2ch = {"FEDCBA9876543210123456789ABCDEF"};
    char * p = buf;
    int old_num = num;

    // 仅支持部分进制
    if ((base != 2) && (base != 8) && (base != 10) && (base != 16)) {
        *p = '\0';
        return;
    }

    // 只支持十进制负数
    int signed_num = 0;
    if ((num < 0) && (base == 10)) {
        *p++ = '-';
        signed_num = 1;
    }

    if (signed_num) {
        do {
            char ch = num2ch[num % base + 15];
            *p++ = ch;
            num /= base;
        } while (num);
    } else {
        uint32_t u_num = (uint32_t)num;
        do {
            char ch = num2ch[u_num % base + 15];
            *p++ = ch;
            u_num /= base;
        } while (u_num);
    }
    *p-- = '\0';

    // 将转换结果逆序，生成最终的结果
    char * start = (!signed_num) ? buf : buf + 1;
    while (start < p) {
        char ch = *start;
        *start = *p;
        *p-- = ch;
        start++;
    }
}

void kernel_sprintf(char *buffer, const char *fmt, ...) 
{
    va_list args;

    va_start(args, fmt);
    kernel_vsprintf(buffer, fmt, args);
    va_end(args);
}

/**
 * 格式化字符串
 */
void kernel_vsprintf(char *buffer, const char *fmt, va_list args) 
{
    enum {NORMAL, READ_FMT} state = NORMAL;
    char ch;
    char * curr = buffer;
    while ((ch = *fmt++)) {
        switch (state) {
            // 普通字符
            case NORMAL:
                if (ch == '%') {
                    state = READ_FMT;
                } else {
                    *curr++ = ch;
                }
                break;
            // 格式化控制字符，只支持部分
            case READ_FMT:
                if (ch == 'd') {
                    int num = va_arg(args, int);
                    kernel_itoa(curr, num, 10);
                    curr += kernel_strlen(curr);
                } else if (ch == 'x') {
                    int num = va_arg(args, int);
                    kernel_itoa(curr, num, 16);
                    curr += kernel_strlen(curr);
                } else if (ch == 'c') {
                    char c = va_arg(args, int);
                    *curr++ = c;
                } else if (ch == 's') {
                    const char * str = va_arg(args, char *);
                    int len = kernel_strlen(str);
                    while (len--) {
                        *curr++ = *str++;
                    }
                }
                state = NORMAL;
                break;
        }
    }
}

int strings_count(char **start)
{
    int count = 0;
    if (start) {
        while (*start ++)
        {
            count ++;
        }
        
    }

    return count;
}

char *get_file_name(const char *name)
{
    char *s = name;
    while (*s != '\0')
    {
        s++;
    }
    while ((*s != '/') && (*s != '\\') && (*s >= name))
    {
        s--;
    }

    return s + 1;
}